// Code by Cromwell D. Enage
// April 2009
#ifndef _FULLSAIL_AI_APP_NEURAL_NETWORK_LAB_H_
#define _FULLSAIL_AI_APP_NEURAL_NETWORK_LAB_H_

// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER					// Allow use of features specific to Windows XP or later.
#define WINVER 0x0501			// Change this to the appropriate value to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT			// Allow use of features specific to Windows XP or later.                   
#define _WIN32_WINNT 0x0501		// Change this to the appropriate value to target other versions of Windows.
#endif						

#ifndef _WIN32_WINDOWS			// Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0410	// Change this to the appropriate value to target Windows Me or later.
#endif

#ifndef _WIN32_IE				// Allow use of features specific to IE 6.0 or later.
#define _WIN32_IE 0x0600		// Change this to the appropriate value to target other versions of IE.
#endif

#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers

// Windows Header Files:
#include <windows.h>
#include <commdlg.h>
#include <commctrl.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

// Application-Specific Header Files
#include <iosfwd>
#include <string>
#include <vector>
#include "../../Core/MlpAgent.h"
#include "../Loader.h"
#include "Resource.h"

// VC7.1 thinks pre-incrementing inside a while condition is dangerous.
#if _MSC_VER < 1400
#pragma warning(disable : 4288)
#endif

//! \brief Custodian of global variables needed by all classes in this file.
struct NeuralNetworkGlobals
{
	static const UINT SHOW_NETWORK_TRAINING = 1;
	static const UINT SHOW_NEURONS = 2;

private:
	// singleton instance
	static NeuralNetworkGlobals* instance_;

	// variables
	UINT flags_;

	// singleton members
	NeuralNetworkGlobals();
	NeuralNetworkGlobals(NeuralNetworkGlobals const&);
	NeuralNetworkGlobals& operator=(NeuralNetworkGlobals const&);
	~NeuralNetworkGlobals();

public:
	static NeuralNetworkGlobals* getInstance();

	static void deleteInstance();

	inline UINT isFlagOn(UINT flag) const
	{
		return flags_ & flag;
	}

	inline void turnOn(UINT flag)
	{
		flags_ |= flag;
	}

	inline void turnOff(UINT flag)
	{
		flags_ &= ~flag;
	}
};

class NeuralNetworkLab
{
	static const LONG                      MAX_LOADSTRING = 32;
	static const LONG                      MAX_BUFFER_SIZE = 256;

	// singleton instance
	static NeuralNetworkLab*               instance_;

	// application handle
	HINSTANCE                              application_handle_;

	// list-view column counts
	int                                    training_sets_view_column_count_;
	int                                    hidden_neurons_view_column_count_;
	int                                    output_neurons_view_column_count_;

	// window and tab controls
	HWND                                   window_handle_;
	HWND                                   tab_control_handle_;

	// combo-box and list-view controls
	HWND                                   expected_action_list_handle_;
	HWND                                   training_sets_view_handle_;
	HWND                                   inputs_view_handle_;
	HWND                                   hidden_neurons_view_handle_;
	HWND                                   output_neurons_view_handle_;
	HWND                                   init_params_view_handle_;

	// button controls
	HWND                                   open_button_handle_;
	HWND                                   reset_button_handle_;
	HWND                                   run_button_handle_;
	HWND                                   step_button_handle_;

	// custom windows
	HWND                                   outputs_handle_;

	// double-buffering primitives
	HDC                                    outputs_device_context_handle_;
	HDC                                    outputs_buffer_context_handle_;
	HBITMAP                                outputs_buffer_bitmap_handle_;

	// run-button icons
	HICON                                  pause_icon_handle_;
	HICON                                  play_icon_handle_;

	// coordinates, offsets, and dimensions
	int                                    expected_action_label_x_;
	int                                    expected_action_label_y_;
	int                                    outputs_window_x_;
	int                                    outputs_window_y_;
	int                                    outputs_window_width_;
	int                                    outputs_window_height_;
	int                                    outputs_width_;
	int                                    outputs_height_;
	POINT                                  outputs_offset_;

	// synchronization primitives
	volatile bool                          cannot_close_thread_handle_;
	volatile bool                          should_stop_thread_handle_;
	mutable CRITICAL_SECTION               smith_sync_;
	CRITICAL_SECTION                       thread_sync_;
	DWORD                                  thread_id_;
	HANDLE                                 thread_handle_;

	// neural network initialization arguments
	std::size_t                            current_hidden_neuron_count_;
	double                                 current_learning_factor_;

	// neural network display items
	std::vector<std::basic_string<TCHAR> > input_strings_;
	std::vector<std::basic_string<TCHAR> > action_strings_;
	std::vector<std::vector<double> >      sample_inputs_;
	std::vector<std::vector<double> >      expected_outputs_;
	std::vector<HBITMAP>                   action_bitmap_handles_;

	// neural network variables
	fullsail_ai::MlpAgent                  smith_;
	std::vector<double>                    current_inputs_;
	INT                                    current_example_index_;
	std::size_t                            iteration_cycle_;

	// title bar strings
	TCHAR                                  title_text_[MAX_LOADSTRING];
	TCHAR                                  title_bar_text_[MAX_BUFFER_SIZE];

	// neural network input and parameter names
	TCHAR                                  hidden_neuron_count_param_text_[20];
	TCHAR                                  learning_factor_param_text_[16];
	TCHAR                                  select_me_text_[10];

	// the file filter string
	TCHAR                                  text_filter_[12];

	// tooltip strings
	TCHAR                                  open_button_text_[5];
	TCHAR                                  reset_button_text_[6];
	TCHAR                                  run_button_text_[4];
	TCHAR                                  step_button_text_[5];

	// singleton declarations
	NeuralNetworkLab();
	NeuralNetworkLab(NeuralNetworkLab const&);
	NeuralNetworkLab& operator=(NeuralNetworkLab const&);
	~NeuralNetworkLab();

public:
	static NeuralNetworkLab* getInstance();
	static void deleteInstance();

	// Needed by the window procedure.
	inline HINSTANCE getApplicationHandle() const
	{
		return application_handle_;
	}

private:
	void removeBitmaps_();
	void resetOffsets_();
	void stopRun_();
	bool isReady_() const;
	BOOL shouldEnableButtons_() const;
	void updateButtons_();
	void updateOutputsWindowAndExpectedAction_();
	void updateEditableListViews_();
	void updateVisibleListViews_();
	void initializeAgent_();
	void initializeUserInterface_();
	void openFile_(HWND window_handle, TCHAR const* file_name);

public:
	BOOL initializeApplication(HINSTANCE application_handle, int n_cmd_show);

	// Thread callback helper methods.
private:
	void run_();

public:
	void threadHandler();

	// Event handler for tab selection.
	void onTabSelection();

	// Event handlers for push-button presses.
	void onReset();
	void onRun();
	void onStep();

	// Event handler for key presses.
	bool onKeyPress(WPARAM w_param);

	// Event handler for combo boxes.
	void onComboBox(WORD hi_word);

	// Event handler for list-views.
	LRESULT onListView(LPARAM l_param);

	// Event handler for resizing the outputs window.
	void onSize(HWND window_handle, WPARAM w_param, LPARAM l_param);

	// Event handler for horizontal scrolling of the outputs window.
	void onHScroll(HWND window_handle, WPARAM w_param, LPARAM l_param);

	// Event handler for vertical scrolling of the outputs window.
	void onVScroll(HWND window_handle, WPARAM w_param, LPARAM l_param);

	// Event handler for file opening.
	void onFileOpen(HWND window_handle);

	// Event handler for rendering the labels in the main window.
	void paintLabels(HDC device_context_handle) const;

	// Event handler for rendering the outputs near the lower-right-hand corner.
	void paintOutputs(HDC device_context_handle) const;

private:
	void paintOutputs_(HDC device_context_handle, HDC buffer_context_handle) const;
};

#endif  // _FULLSAIL_AI_APP_NEURAL_NETWORK_LAB_H_

